# 导入MaixCAM所需的模块
from maix import pwm, time, pinmap, err, sys
# 导入HTTP请求和JSON处理模块
import requests
import json

# 舵机控制参数定义
SERVO_PERIOD = 50     # 舵机控制频率50Hz，对应20ms周期
SERVO_MIN_DUTY = 2.5  # 最小占空比2.5%，对应0.5ms脉宽，控制舵机转到0度
SERVO_MAX_DUTY = 12.5  # 最大占空比12.5%，对应2.5ms脉宽，控制舵机转到180度

# HTTP API配置
API_URL = "https://api.wenfree.cn/MaixCAM_Index/get_angle"  # API接口地址
REQUEST_INTERVAL = 0.1  # HTTP请求间隔0.5秒


# 根据设备ID获取对应的引脚和PWM编号
# 不同型号的MaixCAM设备使用不同的GPIO引脚
device_id = sys.device_id()
if device_id == "maixcam2":
    pin_name = "IO0_A31"  # MaixCAM2使用IO0_A31引脚
    pwm_id = 7           # PWM通道7
else:
    pin_name = "A19"     # 其他设备使用A19引脚
    pwm_id = 7           # PWM通道7

# 打印设备信息，用于调试
# print("device_id", device_id['name'], device_id['id'])

# 设置引脚映射（当前已注释，如需要可取消注释）
# 将指定引脚配置为PWM功能
# err.check_raise(pinmap.set_pin_function(pin_name, f"PWM{pwm_id}"), "set pinmap failed")
# 注意：某些MaixCAM版本可能需要启用此功能



def angle_to_duty(percent):
    """
    将角度百分比转换为PWM占空比
    
    参数:
        percent: 角度百分比，0-100对应舵机0度-180度
    
    返回:
        对应的PWM占空比（2.5%-12.5%）
    
    原理:
        - 0%   -> 2.5%占空比  -> 0.5ms脉宽  -> 0度
        - 50%  -> 7.5%占空比  -> 1.5ms脉宽  -> 90度  
        - 100% -> 12.5%占空比 -> 2.5ms脉宽  -> 180度
    """
    return (SERVO_MAX_DUTY - SERVO_MIN_DUTY) * percent / 100.0 + SERVO_MIN_DUTY

def angle_degrees_to_duty(angle_degrees):
    """
    将角度（0-180度）直接转换为PWM占空比
    
    参数:
        angle_degrees: 角度值，0-180度（MG90S舵机范围）
    
    返回:
        对应的PWM占空比（2.5%-12.5%）
    """
    # 限制角度范围在0-180度之间
    if angle_degrees < 0:
        angle_degrees = 0
    elif angle_degrees > 180:
        angle_degrees = 180
    
    # 将角度转换为百分比，再转换为占空比
    percent = angle_degrees / 180.0 * 100.0
    return angle_to_duty(percent)

def get_angle_from_api():
    """
    从API获取角度数据
    
    返回:
        成功: 角度值（float，0-180度）
        失败: None
        
    API响应格式（实际）:
        {
            "data": {
                "angle": 180,
                "status": "success",
                "cached": "yes",
                "source": "redis"
            },
            "code": 200,
            "message": "获取角度成功"
        }
    """
    try:
        # 发送HTTP GET请求，设置5秒超时
        print(f"正在请求API: {API_URL}")
        response = requests.get(API_URL, timeout=5)
        
        # 检查HTTP状态码
        if response.status_code == 200:
            # 打印原始响应内容
            print(f"HTTP响应状态码: {response.status_code}")
            print(f"原始响应内容: {response.text}")
            
            # 解析JSON响应
            data = response.json()
            print(f"解析后的JSON数据: {data}")
            
            # 检查API返回的状态码（使用'code'字段而不是'ret'）
            if 'code' in data and data['code'] == 200:
                # 提取角度数据
                if 'data' in data and 'angle' in data['data']:
                    angle = float(data['data']['angle'])
                    status = data['data'].get('status', 'unknown')
                    cached = data['data'].get('cached', 'unknown')
                    source = data['data'].get('source', 'unknown')
                    message = data.get('message', '未知消息')
                    
                    print(f"=== API响应解析成功 ===")
                    print(f"消息: {message}")
                    print(f"角度: {angle}°")
                    print(f"状态: {status}")
                    print(f"缓存状态: {cached}")
                    print(f"数据源: {source}")
                    print(f"========================")
                    
                    return angle
                else:
                    print("API响应格式错误: 缺少data.angle字段")
                    print(f"data字段内容: {data.get('data', '无data字段')}")
                    return None
            else:
                print(f"API返回错误状态码: {data.get('code', '无code字段')}")
                print(f"错误消息: {data.get('message', '未知错误')}")
                return None
        else:
            print(f"HTTP请求失败: 状态码 {response.status_code}")
            print(f"响应内容: {response.text}")
            return None
            
    except requests.exceptions.Timeout:
        print("请求超时（5秒）")
        return None
    except requests.exceptions.ConnectionError:
        print("连接错误，请检查网络连接")
        return None
    except json.JSONDecodeError as e:
        print(f"JSON解析错误: {str(e)}")
        print(f"响应内容: {response.text if 'response' in locals() else '无响应'}")
        return None
    except Exception as e:
        print(f"未知错误: {str(e)}")
        print(f"错误类型: {type(e).__name__}")
        return None

def http_servo_control():
    """
    HTTP控制舵机主函数
    每0.5秒从API获取角度数据并控制舵机
    """
    print("开始HTTP舵机控制模式...")
    print(f"API地址: {API_URL}")
    print(f"请求间隔: {REQUEST_INTERVAL}秒")
    
    # 创建PWM对象，初始化为90度（中间位置）
    servo = pwm.PWM(pwm_id, freq=SERVO_PERIOD, duty=angle_degrees_to_duty(90), enable=True)
    print("舵机初始化完成，当前位置: 90度")
    
    # 等待舵机到达初始位置
    time.sleep(1)
    
    print("开始HTTP轮询控制，按Ctrl+C停止...")
    
    # 记录上一次角度，避免重复设置
    last_angle = 90
    
    try:
        while True:
            # 从API获取角度数据
            angle = get_angle_from_api()
            
            if angle is not None:
                # 检查角度变化是否超过0.5度（避免频繁小幅调整）
                if abs(angle - last_angle) > 0.5:
                    # 设置新角度
                    duty = angle_degrees_to_duty(angle)
                    servo.duty(duty)
                    print(f"舵机更新: {last_angle}° -> {angle}° (占空比: {duty:.2f}%)")
                    last_angle = angle
                else:
                    print(f"角度无显著变化: {angle}° (跳过)")
            else:
                print("获取角度失败，保持当前位置")
            
            # 等待下次请求
            time.sleep(REQUEST_INTERVAL)
            
    except KeyboardInterrupt:
        print("\n用户中断程序")
    except Exception as e:
        print(f"程序错误: {str(e)}")
    finally:
        # 程序结束时回到中间位置
        servo.duty(angle_degrees_to_duty(90))
        print("舵机回到中间位置，程序结束")


# ================================
# 主程序选择：可以选择运行测试模式或HTTP控制模式
# ================================

# 选择运行模式：True=HTTP控制模式，False=测试模式
HTTP_CONTROL_MODE = True

if HTTP_CONTROL_MODE:
    # HTTP控制模式：从API获取角度数据控制舵机
    http_servo_control()
else:
    # 测试模式：舵机来回摆动测试（原始功能）
    print("开始舵机测试模式...")
    
    # 创建PWM对象，初始化舵机控制
    # pwm_id: PWM通道号
    # freq: PWM频率50Hz
    # duty: 初始占空比，设置为0%对应0度位置
    # enable: 立即启用PWM输出
    out = pwm.PWM(pwm_id, freq=SERVO_PERIOD, duty=angle_to_duty(0), enable=True)
    
    # 第一个循环：舵机从0度缓慢转动到180度
    # i从0到99，对应角度从0%到99%（约0度到178度）
    for i in range(100):
        out.duty(angle_to_duty(i))  # 设置新的PWM占空比
        time.sleep_ms(100)          # 延时100毫秒，控制转动速度
    
    # 第二个循环：舵机从180度缓慢转回0度  
    # (100-i)从100到1，对应角度从100%到1%（约180度到1.8度）
    for i in range(100):
        out.duty(angle_to_duty(100 - i))  # 设置新的PWM占空比
        time.sleep_ms(100)                # 延时100毫秒，控制转动速度
    
    print("舵机测试完成")

# ================================
# 使用说明：
# 1. 设置 HTTP_CONTROL_MODE = True 启用HTTP控制模式
# 2. 设置 HTTP_CONTROL_MODE = False 启用测试模式
# 3. HTTP模式需要网络连接和requests库
# 4. 测试模式用于验证舵机硬件功能
# 5. 可通过修改API_URL更改API地址
# 6. 可通过修改REQUEST_INTERVAL调整请求频率
# ================================